package com.h6.crm.service.Impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.h6.crm.entity.Brand;
import com.h6.crm.entity.Client;
import com.h6.crm.entity.FollowRecord;
import com.h6.crm.entity.HrEmployee;
import com.h6.crm.entity.Project;
import com.h6.crm.entity.QuoteRecord;
import com.h6.crm.entity.SysUser;
import com.h6.crm.mapper.FollowMapper;
import com.h6.crm.mapper.ProjectMapper;
import com.h6.crm.service.AttachmentService;
import com.h6.crm.service.BrandService;
import com.h6.crm.service.ClientService;
import com.h6.crm.service.HrEmployeeService;
import com.h6.crm.service.ProjectService;
import com.h6.crm.service.QuoteService;
import com.h6.crm.util.Constant;
import com.h6.crm.util.pojo.ResultCode;
import com.h6.crm.util.pojo.ServiceException;
import com.h6.crm.util.pojo.dto.FollowRecordDto;
import com.h6.crm.util.pojo.dto.QuoteDto;
import com.h6.crm.util.pojo.vo.QueryProjectVO;
import com.h6.crm.util.pojo.vo.QueryQuoteReocrdVO;
import com.h6.crm.util.pojo.vo.QuoteVO;
import com.h6.crm.util.pojo.vo.ReportProjectVO;
import com.h6.crm.util.pojo.vo.SaveFollowVO;
import com.h6.crm.util.pojo.vo.UpdateProjectStatusVO;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> implements ProjectService {

    @Autowired
    ProjectMapper projectMapper;

    @Autowired
    ClientService clientService;

    @Autowired
    QuoteService quoteService;

    @Autowired
    FollowMapper followMapper;

    @Autowired
    AttachmentService attachmentService;

    @Autowired
    HrEmployeeService employeeService;

    @Autowired
    BrandService brandService;

    @Override
    public IPage<Project> queryProjectList(QueryProjectVO projectVo) {
        QueryWrapper<Project> queryWrapper = new QueryWrapper<Project>();
        queryWrapper.ge(ObjectUtil.isNotNull(projectVo.getStartDate()), "FORMAT(OperationDate, 'yyyy-MM-dd')",
                projectVo.getStartDate());
        queryWrapper.le(ObjectUtil.isNotNull(projectVo.getEndDate()), "FORMAT(OperationDate, 'yyyy-MM-dd')",
                projectVo.getEndDate()).lambda()
                .like(StrUtil.isNotBlank(projectVo.getProjectName()), Project::getName, projectVo.getProjectName())
                .eq(StrUtil.isNotBlank(projectVo.getSource()), Project::getSource, projectVo.getSource())
                .eq(StrUtil.isNotBlank(projectVo.getProvince()), Project::getProvince, projectVo.getProvince())
                .eq(StrUtil.isNotBlank(projectVo.getCity()), Project::getCity, projectVo.getCity())
                .eq(StrUtil.isNotBlank(projectVo.getProjectStatus()), Project::getProjectStatus,
                        projectVo.getProjectStatus())
                .eq(ObjectUtil.isNotNull(projectVo.getSalesmanId()), Project::getSalesmanId, projectVo.getSalesmanId())
                .orderByDesc(Project::getOperationDate).orderByDesc(Project::getId);
        Page<Project> projectPage = page(new Page<Project>(projectVo.getPage(), projectVo.getPageSize()), queryWrapper);
        List<Project> projectList = projectPage.getRecords();
        Client client;
        HrEmployee employee;
        Brand brand;
        Map<Long, Client> clientCache = new HashMap<>();
        Map<Long, HrEmployee> userCache = new HashMap<>();
        Map<Long, Brand> brandCache = new HashMap<>();
        for (Project project : projectList) {
            if (ObjectUtil.isNotNull(project.getClientId())) {
                client = clientCache.get(project.getClientId());
                if (ObjectUtil.isNull(client)) {
                    client = clientService.getById(project.getClientId());
                    if (ObjectUtil.isNotNull(client)) {
                        clientCache.put(client.getId(), client);
                        project.setClientName(client.getName());
                    }
                } else {
                    project.setClientName(client.getName());
                }
            }
            employee = userCache.get(project.getSalesmanId());
            if (ObjectUtil.isNull(employee)) {
                employee = employeeService.getById(project.getSalesmanId());
                if (ObjectUtil.isNotNull(employee)) {
                    userCache.put(employee.getEmplId(), employee);
                    project.setSalesman(employee.getEmplName());
                }
            } else {
                project.setSalesman(employee.getEmplName());
            }
            if (ObjectUtil.isNotNull(project.getEntityId())) {
                brand = brandCache.get(project.getEntityId());
                if (ObjectUtil.isNull(brand)) {
                    brand = brandService.getById(project.getEntityId());
                    brandCache.put(project.getEntityId(), brand);
                    if (ObjectUtil.isNull(brand)) {
                        continue;
                    }
                }
                project.setEntity(brand.getName());
            }
        }
        projectPage.setRecords(projectList);
        return projectPage;
    }

    @Override
    public Boolean reportProject(ReportProjectVO reportProjectVO, SysUser user) {
        // 检查项目是否已报备
        if (exists(new LambdaQueryWrapper<Project>()
                .ne(ObjectUtil.isNotNull(reportProjectVO.getId()), Project::getId, reportProjectVO.getId())
                .ne(Project::getProjectStatus, Constant.PROJECT_STATUS3)
                .eq(Project::getName, reportProjectVO.getName()))) {
            throw new ServiceException("项目已经报备，请检查");
        }
        Project project = new Project();
        BeanUtil.copyProperties(reportProjectVO, project);
        Client client = clientService.getOne(new LambdaQueryWrapper<Client>()
                .eq(Client::getName, reportProjectVO.getClientName()));
        if (ObjectUtil.isNull(client)) {
            client = new Client();
            client.setName(reportProjectVO.getClientName());
            client.setClientCode(clientService.generatorClientCode());
            client.setBillType(15);
            client.setPayment("出运后");
            client.setPaymentMethodID(1);
            client.setCompanyId(1);
            client.setCurrencyID(1);
            client.setEnabled(false);
            client.setUpId(1);
            client.setEmplId(user.getEmplID());
            clientService.save(client);
        }
        if (ObjectUtil.isNull(project.getId())) {
            project.setSalesmanId(user.getEmplID());
            project.setProjectStatus(Constant.PROJECT_STATUS1);
            project.setOperationDate(new Date());
        } else {
            if (StrUtil.equals(Constant.PROJECT_STATUS3, reportProjectVO.getProjectStatus())
                    && StrUtil.isBlank(reportProjectVO.getRemark())) {
                throw new ServiceException("项目终止，需备注原因");
            }
        }
        project.setClientId(client.getId());
        return saveOrUpdate(project);
    }

    @Override
    public void saveFollow(Long projectId, SaveFollowVO saveFollowVo) {
        if (!exists(new LambdaQueryWrapper<Project>()
                .eq(Project::getId, projectId))) {
            throw new ServiceException(ResultCode.DATA_NOT_EXISTS);
        }
        FollowRecord record = new FollowRecord();
        record.setContent(saveFollowVo.getContent());
        record.setProjectId(projectId);
        followMapper.insert(record);
        try {
            attachmentService.dealFile(saveFollowVo.getAttachmentPath(), record.getId(), Constant.ATTACHMENT_FOLLOW,
                    null);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new ServiceException(ResultCode.ATTACHMENT_UPLOAD_FAILD);
        }
    }

    @Override
    public List<FollowRecordDto> queryFollowReocrdList(Long projectId) {
        return followMapper.queryFollowReocrdList(projectId);

    }

    @Override
    public void quote(Long projectId, QuoteVO quoteVO, SysUser user) {
        Project project = getById(projectId);
        if (ObjectUtils.isNull(project)) {
            throw new ServiceException(ResultCode.DATA_NOT_EXISTS);
        }
        QuoteRecord quoteRecord = new QuoteRecord();
        BeanUtil.copyProperties(quoteVO, quoteRecord);
        quoteRecord.setProjectId(projectId);
        quoteRecord.setBidderId(user.getEmplID());
        quoteRecord.setQuoteDate(new Date());
        quoteService.saveOrUpdate(quoteRecord);
        project.setQuoteAmount(quoteVO.getAmount());
        updateById(project);
        try {
            attachmentService.dealFile(quoteVO.getAttachmentPath(), quoteRecord.getId(), Constant.ATTACHMENT_QUOTE,
                    null);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new ServiceException(ResultCode.ATTACHMENT_UPLOAD_FAILD);
        }
    }

    @Override
    public List<QuoteDto> queryQuoteReocrdList(Long projectId, QueryQuoteReocrdVO recordVo) {
        QueryWrapper<QuoteRecord> queryWrapper = new QueryWrapper<QuoteRecord>();
        queryWrapper.ge(ObjectUtil.isNotNull(recordVo.getStartDate()), "FORMAT(QuoteDate, 'yyyy-MM-dd')",
                recordVo.getStartDate());
        queryWrapper.le(ObjectUtil.isNotNull(recordVo.getEndDate()), "FORMAT(QuoteDate, 'yyyy-MM-dd')",
                recordVo.getEndDate())
                .lambda().eq(QuoteRecord::getProjectId, projectId)
                .eq(StrUtil.isNotBlank(recordVo.getQuoteStatus()), QuoteRecord::getQuoteStatus,
                        recordVo.getQuoteStatus())
                .orderByDesc(QuoteRecord::getQuoteDate).orderByDesc(QuoteRecord::getId);
        List<QuoteRecord> quoteRecords = quoteService.list(queryWrapper);
        List<QuoteDto> quoteDtoList = new ArrayList<>(quoteRecords.size());
        Map<Long, Brand> brandCache = new HashMap<>();
        quoteRecords.forEach(
                quote -> {
                    QuoteDto quoteDto = new QuoteDto();
                    quoteDto.setId(quote.getId());
                    quoteDto.setAmount(quote.getAmount());
                    if (ObjectUtil.isNotNull(quote.getEntityId())) {
                        Brand brand = brandCache.get(quote.getEntityId());
                        if (ObjectUtil.isNull(brand)) {
                            brand = brandService.getById(quote.getEntityId());
                            brandCache.put(quote.getEntityId(), brand);
                            if (ObjectUtil.isNotNull(brand)) {
                                quoteDto.setEntity(brand.getName());
                            }
                        } else {
                            quoteDto.setEntity(brand.getName());
                        }
                    }
                    quoteDto.setProjectId(quote.getProjectId());
                    quoteDto.setNumber(quote.getNumber());
                    quoteDto.setFloatingPercentage(quote.getFloatingPercentage());
                    quoteDto.setQuoteDate(quote.getQuoteDate());
                    quoteDto.setQuoteStatus(quote.getQuoteStatus());
                    quoteDtoList.add(quoteDto);
                });
        return quoteDtoList;

    }

    @Override
    public Project getProjectDetailById(Long projectId) {
        return projectMapper.getProjectDetailById(projectId);

    }

    @Override
    public Boolean updateProjectStatus(Long projectId, UpdateProjectStatusVO projectVO) {
        Project project = getById(projectId);
        if (ObjectUtils.isNull(project)) {
            throw new ServiceException(ResultCode.DATA_NOT_EXISTS);
        }
        if (StrUtil.equals(Constant.PROJECT_STATUS3, projectVO.getProjectStatus())
                && StrUtil.isBlank(projectVO.getRemark())) {
            throw new ServiceException("项目终止，需备注原因");
        }
        project.setProjectStatus(projectVO.getProjectStatus());
        project.setRemark(projectVO.getRemark());
        return updateById(project);
    }

    @Override
    public List<String> queryNameList(String projectName) {
        return list(new LambdaQueryWrapper<Project>()
                .like(StrUtil.isNotBlank(projectName), Project::getName, projectName.strip())
                .ne(Project::getProjectStatus, Constant.PROJECT_STATUS3)
                .select(Project::getName)
                .orderByAsc(Project::getName)).stream().map(Project::getName).collect(Collectors.toList());
    }
}